import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:crypto/crypto.dart';
import '../models/book.dart';
import '../main.dart' show ReadingSettings;
import 'dart:io';
import 'package:path_provider/path_provider.dart';

// 章节索引结构
class ChapterIndex {
  final String title;
  final int startOffset;
  final int endOffset;

  ChapterIndex({
    required this.title,
    required this.startOffset,
    required this.endOffset,
  });

  Map<String, dynamic> toJson() => {
    'title': title,
    'startOffset': startOffset,
    'endOffset': endOffset,
  };

  factory ChapterIndex.fromJson(Map<String, dynamic> json) => ChapterIndex(
    title: json['title'],
    startOffset: json['startOffset'],
    endOffset: json['endOffset'],
  );
}

class BookDataManager {
  static String getBookId(Book book) {
    if (book.path != null) {
      return md5.convert(utf8.encode(book.name + book.path!)).toString();
    } else if (book.contentBase64 != null) {
      return md5
          .convert(utf8.encode(book.name + book.contentBase64!))
          .toString();
    } else {
      return md5.convert(utf8.encode(book.name)).toString();
    }
  }

  // 阅读进度
  static Future<void> saveReadingProgress(
    Book book,
    int chapterIndex,
    double scrollOffset,
  ) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    final data = {
      'chapterIndex': chapterIndex,
      'scrollOffset': scrollOffset,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
    };
    await prefs.setString('reading_progress_$bookId', jsonEncode(data));
  }

  static Future<Map<String, dynamic>?> loadReadingProgress(Book book) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    final jsonStr = prefs.getString('reading_progress_$bookId');
    if (jsonStr == null) return null;
    return jsonDecode(jsonStr);
  }

  // 书签
  static Future<void> addBookmark(
    Book book,
    int chapterIndex,
    double scrollOffset,
    String chapterTitle,
  ) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    final key = 'bookmarks_$bookId';
    final bookmarks =
        (prefs.getStringList(key) ?? [])
            .map((e) => jsonDecode(e) as Map<String, dynamic>)
            .toList();
    bookmarks.add({
      'chapterIndex': chapterIndex,
      'scrollOffset': scrollOffset,
      'chapterTitle': chapterTitle,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
    });
    await prefs.setStringList(key, bookmarks.map(jsonEncode).toList());
  }

  static Future<List<Map<String, dynamic>>> getBookmarks(Book book) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    final key = 'bookmarks_$bookId';
    return (prefs.getStringList(key) ?? [])
        .map((e) => jsonDecode(e) as Map<String, dynamic>)
        .toList();
  }

  static Future<void> deleteBookmark(Book book, int index) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    final key = 'bookmarks_$bookId';
    final bookmarks = (prefs.getStringList(key) ?? []).toList();
    if (index >= 0 && index < bookmarks.length) {
      bookmarks.removeAt(index);
      await prefs.setStringList(key, bookmarks);
    }
  }

  // 阅读设置
  static Future<void> saveBookSettings(
    Book book,
    ReadingSettings settings,
  ) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    await prefs.setString(
      'reading_settings_$bookId',
      jsonEncode(settings.toJson()),
    );
  }

  static Future<ReadingSettings> loadBookSettings(Book book) async {
    final prefs = await SharedPreferences.getInstance();
    final bookId = getBookId(book);
    final jsonStr = prefs.getString('reading_settings_$bookId');
    if (jsonStr == null) return ReadingSettings();
    return ReadingSettings.fromJson(jsonDecode(jsonStr));
  }

  // 章节索引相关
  static Future<String> _getIndexFilePath(String bookId) async {
    final dir = await getApplicationDocumentsDirectory();
    final indexDir = Directory('${dir.path}/chapter_index');
    if (!await indexDir.exists()) await indexDir.create();
    return '${indexDir.path}/$bookId.index.json';
  }

  static Future<List<ChapterIndex>> buildChapterIndex(
    String filePath,
    String bookId,
  ) async {
    final file = File(filePath);
    final raf = await file.open();
    final List<ChapterIndex> indexList = [];
    int offset = 0;
    int? chapterStart;
    String? chapterTitle;
    final chapterReg = RegExp(r'^第[\d一二三四五六七八九十百千]+章.*');
    Stream<List<int>> inputStream = file.openRead();
    final lines = inputStream
        .transform(utf8.decoder)
        .transform(const LineSplitter());

    await for (String line in lines) {
      if (chapterReg.hasMatch(line)) {
        if (chapterStart != null && chapterTitle != null) {
          indexList.add(
            ChapterIndex(
              title: chapterTitle,
              startOffset: chapterStart,
              endOffset: offset,
            ),
          );
        }
        chapterStart = offset;
        chapterTitle = line.trim();
      }
      offset += utf8.encode(line + '\n').length;
    }
    // 最后一章
    if (chapterStart != null && chapterTitle != null) {
      indexList.add(
        ChapterIndex(
          title: chapterTitle,
          startOffset: chapterStart,
          endOffset: offset,
        ),
      );
    }
    await raf.close();

    // 保存索引
    final indexFile = File(await _getIndexFilePath(bookId));
    await indexFile.writeAsString(
      jsonEncode(indexList.map((e) => e.toJson()).toList()),
    );
    return indexList;
  }

  static Future<List<ChapterIndex>> loadChapterIndex(String bookId) async {
    final indexFile = File(await _getIndexFilePath(bookId));
    if (!await indexFile.exists()) return [];
    final content = await indexFile.readAsString();
    final List<dynamic> jsonList = jsonDecode(content);
    return jsonList.map((e) => ChapterIndex.fromJson(e)).toList();
  }

  static Future<String> readChapterContent(
    String filePath,
    ChapterIndex index,
  ) async {
    final file = File(filePath);
    final raf = await file.open();
    await raf.setPosition(index.startOffset);
    final length = index.endOffset - index.startOffset;
    final bytes = await raf.read(length);
    await raf.close();
    return utf8.decode(bytes);
  }
}
